﻿using Autofac;
using MgSoft.K3Cloud.WebApi.Dto;
using MgSoft.K3Cloud.WebApi.Exceptions;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading;

namespace MgSoft.K3Cloud.WebApi
{
    /// <summary>
    /// 金蝶连接信息缓存服务
    /// </summary>
    public class KingdeeClientInfoMemoryService
    {
        /// <summary>
        /// 容器生命周期对象
        /// </summary>
        public ILifetimeScope lifetimeScope { get; set; }
        ApiServerInfo apiServerInfo => lifetimeScope.Resolve<ApiServerInfo>();
        /// <summary>
        /// 金蝶接口定义
        /// </summary>
        private K3CloudApiExecuter k3CloudClient { get; set; }
        /// <summary>
        /// 锁对象
        /// </summary>
        readonly object iLock = new object();

        private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

        public K3CloudApiExecuter Get()
        {
            try
            {
                var k3CloudClientInfo = lifetimeScope.Resolve<K3CloudClientInfo>();
                var milliSecond = (DateTime.Now - k3CloudClientInfo.LoginSuccessTime)?.TotalMilliseconds ?? -1;
                lock (iLock)
                {
                    if (milliSecond < 5 * 60 * 1000 && milliSecond > 0) //五分钟
                        return k3CloudClient;
                    else if (milliSecond > 5 * 60 * 1000) //五分钟
                    {
                        k3CloudClient.Logout(k3CloudClientInfo);
                        k3CloudClient = lifetimeScope.Resolve<K3CloudApiExecuter>();
                        loginK3Cloud(k3CloudClientInfo);
                        return k3CloudClient;
                    }
                    else
                    {
                        /*
                         * 由于 K3CloudClientInfo 对象的注入形式是单例的，所以当这个对象第一次被初始化的时候应该所有信息都是空的；
                         * 目前遇到的一个案例是，K3CloudClientInfo的信息不是通过ApiServerInfo(读取登录信息文件)来获取，而是由界面录入，
                         * 所以通过LoginSuccessTime属性来判断是否登录过。通过UserName来判断是否已经被编辑过，如果没被编辑过，则通过ApiServerInfo构建基本信息。否则使用现有信息进行登录校验。
                         */
                        if (string.IsNullOrWhiteSpace(k3CloudClientInfo.UserName)) k3CloudClientInfo = new K3CloudClientInfo(apiServerInfo);
                        k3CloudClient = lifetimeScope.Resolve<K3CloudApiExecuter>();
                        loginK3Cloud(k3CloudClientInfo);
                        return k3CloudClient;
                    }
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //public K3CloudClientInfo Get()
        //{

        //    try
        //    {
        //        var k3CloudClientInfo = lifetimeScope.Resolve<K3CloudClientInfo>();
        //        var milliSecond = (DateTime.Now - k3CloudClientInfo.LoginSuccessTime)?.TotalMilliseconds ?? -1;

        //        _lock.EnterReadLock();
        //        try
        //        {
        //            if (milliSecond < 5 * 60 * 1000 && milliSecond > 0) //五分钟
        //                return k3CloudClientInfo;
        //        }
        //        catch (Exception ex)
        //        {
        //            throw ex;
        //        }
        //        finally { _lock.ExitReadLock(); }

        //        _lock.EnterWriteLock();
        //        try
        //        {
        //            if (milliSecond > 5 * 60 * 1000) //五分钟
        //            {
        //                k3CloudClient.Logout(k3CloudClientInfo);
        //                k3CloudClientInfo = new K3CloudClientInfo(apiServerInfo);
        //                loginK3Cloud(k3CloudClientInfo);
        //            }
        //            else if (milliSecond == -1)
        //            {
        //                /*
        //                 * 由于 K3CloudClientInfo 对象的注入形式是单例的，所以当这个对象第一次被初始化的时候应该所有信息都是空的；
        //                 * 目前遇到的一个案例是，K3CloudClientInfo的信息不是通过ApiServerInfo(读取登录信息文件)来获取，而是由界面录入，
        //                 * 所以通过LoginSuccessTime属性来判断是否登录过。通过UserName来判断是否已经被编辑过，如果没被编辑过，则通过ApiServerInfo构建基本信息。否则使用现有信息进行登录校验。
        //                 */
        //                if (string.IsNullOrWhiteSpace(k3CloudClientInfo.UserName)) k3CloudClientInfo = new K3CloudClientInfo(apiServerInfo);
        //                loginK3Cloud(k3CloudClientInfo);
        //            }

        //            return k3CloudClientInfo;
        //        }
        //        catch (Exception ex)
        //        {
        //            throw ex;
        //        }
        //        finally { _lock.ExitWriteLock(); }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw ex;
        //    }
        //}

        private void loginK3Cloud(K3CloudClientInfo k3CloudClientInfo)
        {
            var validateUserResult = k3CloudClient.ValidateUser(k3CloudClientInfo);
            checkValidateUser(validateUserResult);
            k3CloudClientInfo.LoginSuccessTime = DateTime.Now;

            var cookiesCollection = k3CloudClient.kingdeeHttpClient.Cookie.GetCookies(new Uri(k3CloudClientInfo.ServerUrl));
            if ((cookiesCollection?.Count ?? 0) > 0)
            {
                k3CloudClientInfo.kdservice_sessionid = cookiesCollection["kdservice-sessionid"].Value;
                k3CloudClientInfo.ASP_NET_SessionId = cookiesCollection["ASP.NET_SessionId"].Value;
            }
        }

        private void checkValidateUser(string validateUserResult)
        {
            var resultType = JObject.Parse(validateUserResult)["LoginResultType"].Value<int>();

            if (resultType != 1)
            {
                var msg = JObject.Parse(validateUserResult)["Message"].Value<string>();
                throw new KingdeeLogInException(msg);
            }
        }
    }
}
